# -*- coding: utf-8 -*-
# @Time    : 2024/6/28 15:54
# @Author  : yujiahao
# @File    : 02_numpy_slice_index.py
# @description:Numpy索引和切片


'''
在 NumPy 中，如果想要访问，或修改数组中的元素，您可以采用索引或切片的方式，比如使用从 0 开始的索引依次访问数组中的元素，这与 Python 的 list 列表是相同的。

NumPy 提供了多种类型的索引方式，常用方式有两种：基本切片与高级索引。

'''
import numpy as np


# todo 1、切片
def numpy_slice():
    # todo 1.1、基本切片

    '''
    NumPy 内置函数 slice() 可以用来构造切片对象，该函数需要传递三个参数值分别是 start（起始索引）、stop（终止索引） 和 step（步长） ，
    通过它可以实现从原数组的上切割出一个新数组。当成python中的切片来使用，也可以使用冒号这里不说了
    '''
    a = np.arange(10)
    # 生成切片对象
    s = slice(2, 9, 3)  # 从索引2开始到索引9停止，间隔时间为2，
    print(a[s])

    #  todo 1.2、多维数组切片
    '''注意：切片还可以使用省略号“…”，如果在行位置使用省略号，那么返回值将包含所有行元素，反之，则包含所有列元素。'''
    a = np.array([[1, 2, 3], [3, 4, 5], [4, 5, 6]])
    print(a)
    # 从[1:]索引处开始切割
    print(a[1:])

    # 演示一下...，前面说过
    # 创建a数组
    a = np.array([[1, 2, 3], [3, 4, 5], [4, 5, 6]])
    # 返回数组的第二列
    print(a[..., 1])
    # 返回数组的第二行
    print(a[1, ...])
    # 返回第二列后的所有项
    print(a[..., 1:])

    # todo 2、NumPy高级索引
    '''
    NumPy 与 Python 的内置序列相比，它提供了更多的索引方式。在 NumPy 中还可以使用高级索引方式，比如整数数组索引、布尔索引以及花式索引，
    这里主要对上述三种索引方式做详细介绍。
    高级索引返回的是数组的副本（深拷贝），而切片操作返回的是数组视图（浅拷贝）。
    '''


def numpy_index():
    # todo 2.1. 整数数组索引

    '''整数数组索引，它可以选择数组中的任意一个元素，比如，选择第几行第几列的某个元素，'''
    # 创建二维数组
    x = np.array([[1, 2], [3, 4], [5, 6]])
    # [0,1,2]代表行索引;[0,1,0]代表列索引
    y = x[[0, 1, 2], [0, 1, 0]]
    # 将行、列索引组合会得到 (0,0)、(1,1) 和 (2,0) ，它们分别对应着输出结果在原数组中的索引位置。
    print(y)

    print('''\n-----------------------------------☆☆☆分割线☆☆☆----------------------------------------\n''')

    # 获取了 4*3 数组中的四个角上元素，它们对应的行索引是 [0,0] 和 [3,3]，列索引是 [0,2] 和 [0,2]。
    b = np.array([[0, 1, 2],
                  [3, 4, 5],
                  [6, 7, 8],
                  [9, 10, 11]])
    print('原始数组：\n', b)
    print('''\n-----------------------------------☆☆☆分割线☆☆☆----------------------------------------\n''')
    r = np.array([[0, 0], [3, 3]])
    c = np.array([[0, 2], [0, 2]])
    # 获取四个角的元素
    c = b[r, c]
    print(c)

    # 将切片所使用的:或省略号...与整数数组索引结合使用

    d = np.array([[0, 1, 2],
                  [3, 4, 5],
                  [6, 7, 8],
                  [9, 10, 11]])
    # 对行列分别进行切片
    e = d[1:4, 1:3]
    print('''\n-----------------------------------☆☆☆分割线☆☆☆----------------------------------------\n''')
    print(e)
    # 行使用基础索引，对列使用高级索引
    f = d[1:4, [1, 2]]
    print('''\n-----------------------------------☆☆☆分割线☆☆☆----------------------------------------\n''')
    # 显示切片后结果
    print(f)
    # 对行使用省略号
    h = d[..., 1:]
    print('''\n-----------------------------------☆☆☆分割线☆☆☆----------------------------------------\n''')
    print(h)

    # todo 2.2. 布尔数组索引
    '''当输出的结果需要经过布尔运算（如比较运算）时，此时会使用到另一种高级索引方式，即布尔数组索引。'''
    # 返回所有大于6的数字组成的数组
    x = np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11]])
    print(x[x > 6])

    print('''\n-----------------------------------☆☆☆分割线☆☆☆----------------------------------------\n''')

    # 我们可以使用补码运算符来去除 NaN（即非数字元素），如下所示：
    a = np.array([np.nan, 1, 2, np.nan, 3, 4, 5])
    print(a[~np.isnan(a)])

    print('''\n-----------------------------------☆☆☆分割线☆☆☆----------------------------------------\n''')

    # 删除数组中整数元素，如下所示：
    a = np.array([1, 2 + 6j, 5, 3.5 + 5j])
    print(a[np.iscomplex(a)])

    # todo 2.3. 花式索引（拓展知识）
    '''
        花式索引也可以理解为整数数组索引，但是它们之间又略有不同，下面通过示例做简单讲解。（本内容作为拓展知识了解即可）
        花式索引也会生成一个新的副本。
    '''

    # 当原数组是一维数组时，使用一维整型数组作为索引，那么索引结果就是相应索引位置上的元素。
    x = np.array([1, 2, 3, 4])
    print(x[0])

    print('''\n-----------------------------------☆☆☆分割线☆☆☆----------------------------------------\n''')

    # 如果原数组是二维数组，那么索引数组也需要是二维的，索引数组的元素值与被索引数组的每一行相对应
    x = np.arange(32).reshape((8, 4))
    # 分别对应 第4行数据、第2行数据、第1行数据、第7行数据项
    print(x[[4, 2, 1, 7]])

    print('''\n-----------------------------------☆☆☆分割线☆☆☆----------------------------------------\n''')

    # 也可以使用倒序索引数组
    x = np.arange(32).reshape((8, 4))
    print(x[[-4, -2, -1, -7]])

    print('''\n-----------------------------------☆☆☆分割线☆☆☆----------------------------------------\n''')
    # 还可以同时使用多个索引数组，但这种情况下需要添加np.ix_。
    ''' np.ix_ 函数生成两个用于索引的数组，分别表示所选的行和列。然后，我们使用这些数组来索引原始数组 x，从而得到一个新的子数组。
        选择的行是第 1、5、7、2 行，选择的列是第 0、3、1、2 列,其中 [1,5,7,2] 代表行索引，而 [0,3,1,2] 表示与行索引相对应的列索引值，
        也就是行中的元素值会按照列索引值排序。比如，第一行元素，未排序前的顺序是 [4,5,6,7]，经过列索引排序后变成了 [4,7,5,6]。
        np.ix_ 函数非常有用，它可以帮助我们生成用于索引的网格数组，从而方便地选择多维数组的子集。
        在这个示例中，我们使用 np.ix_ 函数选择了特定的行和列，并生成了一个新的子数组。
    '''
    x = np.arange(32).reshape((8, 4))
    print(x[np.ix_([1, 5, 7, 2], [0, 3, 1, 2])])


def main():
    # numpy_slice()
    numpy_index()


if __name__ == '__main__':
    main()
